﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace Platform.Storage.Redis
{
	/// <summary>
	/// Contadores do canal de comunicação com o REDIS
	/// </summary>
	public sealed class ChannelStats
	{
		private object syncSend = new object();
		private object syncReceive = new object();

		private int sent = 0;
		private int received = 0;
		private int errors = 0;
		private int success = 0;
		private long bytesSent = 0L;
		private long bytesReceived = 0L;

		public ChannelStats()
		{
			this.RunningSince = DateTime.Now;
			this.LastReceived = DateTime.Now;
			this.LastSent = DateTime.Now;
		}

		/// <summary>
		/// Obtém a quantidade de mensagens enviadas
		/// </summary>
		public int Sent
		{ get { return this.sent; } }

		/// <summary>
		/// Obtém a quantidade de mensagens recebidas
		/// </summary>
		public int Received
		{ get { return this.received; } }

		/// <summary>
		/// Obtém a quantidade de mensagens recebidas que são erros
		/// </summary>
		public int Errors
		{ get { return this.errors; } }

		/// <summary>
		/// Obtém a quantidade de mensagens recebidas com sucesso
		/// </summary>
		public int Success
		{ get { return this.success; } }

		/// <summary>
		/// Obtém a quantidade de bytes enviados para o REDIS
		/// </summary>
		public long BytesSent
		{ get { return this.bytesSent; } }

		/// <summary>
		/// Obtém a quantidade de bytes recebidos do REDIS
		/// </summary>
		public long BytesReceived
		{ get { return this.bytesReceived; } }

		/// <summary>
		/// Obtém a data a última vez que uma mensagem foi enviada pelo canal
		/// </summary>
		public DateTime LastSent
		{ get; private set; }

		/// <summary>
		/// Obtém a última vez que uma mensagem foi recebido do REDIS
		/// </summary>
		public DateTime LastReceived
		{ get; private set; }

		/// <summary>
		/// Obtém a data e hora que o canel inicializou
		/// </summary>
		public DateTime RunningSince
		{ get; private set; }

		/// <summary>
		/// Indica que uma mensagem foi enviada
		/// </summary>
		/// <param name="messageLen"></param>
		internal void MessageSent( int messageLen )
		{
			this.LastSent = DateTime.Now;

			if ( messageLen < 0 )
				messageLen = 0;

			lock ( this.syncSend )
			{
				this.sent++;
				this.bytesSent += messageLen;
			}
		}

		/// <summary>
		/// Indica que uma mensagem foi recebida com sucesso
		/// </summary>
		/// <param name="messageLen"></param>
		internal void MessageReceived( int messageLen )
		{
			this.MessageReceived( messageLen, false );
		}

		/// <summary>
		/// Indica que um erro foi enviado pelo REDIS
		/// </summary>
		/// <param name="messageLen"></param>
		internal void ErrorReceived( int messageLen )
		{
			this.MessageReceived( messageLen, true );
		}

		private void MessageReceived( int messageLen, bool isError )
		{
			this.LastReceived = DateTime.Now;

			if ( messageLen < 0 )
				messageLen = 0;

			if ( isError )
				Interlocked.Increment( ref this.errors );
			else
				Interlocked.Increment( ref this.success );

			lock ( this.syncReceive )
			{
				this.received++;
				this.bytesReceived += messageLen;
			}
		}
	}
}
